import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import authServices from "./authServices";

/**
 * Экземпляр axios с настройками по умолчанию.
 */
const instance = axios.create({
    // baseURL: 'http://185.65.200.4:23036',
    headers: {
        "Content-Type": "application/json"
    }
});

/**
 * Обработчик ответов 401(неавторизованный запрос) и 403(доступ запрещен).
 */
instance.interceptors.response.use(
    response => response,
    async (error) => {
        const originalConfig = error.config;
        if (error.response) {
            if (error.response.status === 401 && !originalConfig.retry) {
                originalConfig.retry = true;

                try {
                    await authServices.refresh();
                    return instance(originalConfig);

                } catch (_error) {
                    if (_error.response && _error.response.data) {
                        return Promise.reject(_error.response.data);
                    }

                    return Promise.reject(_error);
                }
            }

            if (error.response.status === 403) {
                window.location.replace('/login');
                return Promise.reject(error.response.data);
            }
        }

        return Promise.reject(error);
    }
);

/**
 * @function post - Отправляет POST-запрос.
 * @param { string } url - url для отправки запроса.
 * @param { any } data - Данные запроса. 
 * @param { AxiosRequestConfig<any> } config - Дополнительные настройки запроса.
 * @returns { Promise<AxiosResponse<any>> } - Ответ от сервера.
 */
function post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: any, config?: AxiosRequestConfig<D>): Promise<R> {
    return instance.post(url, data, config);
}

/**
 * @function get - Отправляет GET-запрос.
 * @param { string } url - url для отправки запроса.
 * @param { AxiosRequestConfig<any> } config - Дополнительные настройки запроса.
 * @returns { Promise<AxiosResponse<any>> } - Ответ от сервера. 
 */
function get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R> {
    return instance.get(url, config);
}

/**
 * @function del - Отправляет DELETE-запрос.
 * @param { string } url - url для отправки запроса.
 * @param { AxiosRequestConfig<any> } config - Дополнительные настройки запроса.
 * @returns { Promise<AxiosResponse<any>> } - Ответ от сервера. 
 */
function del<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R> {
    return instance.delete(url, config);
}

/**
 * @function put - Отправляет PUT-запрос.
 * @param { string } url - url для отправки запроса.
 * @param { any } data - Данные запроса. 
 * @param { AxiosRequestConfig<any> } config - Дополнительные настройки запроса.
 * @returns { Promise<AxiosResponse<any>> } - Ответ от сервера.
 */
function put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: any, config?: AxiosRequestConfig<D>): Promise<R> {
    return axios.put(url, data, config);
}

export { post, get, del, put };